<?php

declare(strict_types=1);

namespace Shenlink\Holiya\Lexer;

use RuntimeException;
use Shenlink\Holiya\Token\TokenType;

/**
 * Token 处理器工厂类，用于创建和管理各种 Token 处理器的单例实例。
 */
class TokenHandlerFactory
{
    /**
     * @var TokenHandlerFactory 实例
     */
    private static $instance;

    /**
     * @var ITokenHandler[] 处理器列表
     */
    private static array $handlers = [];

    /**
     * @var array 字符到 Handler 的 map
     */
    private static array $charToHandlerMap = [];

    /**
     * 禁止 new 实例化对象
     */
    private function __construct()
    {
        self::$charToHandlerMap = [
            TokenType::PLUS => new PlusHandler(),
            TokenType::MULTIPLY => new MultiplyHandler(),
            TokenType::DIVIDE => new DivideHandler(),
            TokenType::MODULO => new ModuloHandler(),
            TokenType::LPAREN => new LeftParenHandler(),
            TokenType::RPAREN => new RightParenHandler(),
            TokenType::LBRACE => new LeftBraceHandler(),
            TokenType::RBRACE => new RightBraceHandler(),
            TokenType::LBRACKET => new LeftBracketHandler(),
            TokenType::RBRACKET => new RightBracketHandler(),
            TokenType::COMMA => new CommaHandler(),
            TokenType::SEMICOLON => new SemicolonHandler(),
            TokenType::COLON => new ColonHandler(),
        ];
    }

    /**
     * 获取单例
     *
     * @return TokenHandlerFactory 实例
     */
    public static function getInstance(): self
    {
        if (null === self::$instance) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * 防止克隆
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * 禁止反序列化
     *
     * @return void
     * @throws RuntimeException 如果尝试反序列化已存在的实例，则抛出异常
     */
    public function __wakeup()
    {
        if (self::$instance !== null) {
            throw new RuntimeException('反序列化不被允许');
        }

        self::$instance = $this;
    }

    /**
     * 根据词法分析器获取相应的令牌处理器
     *
     * @param Lexer $lexer 词法分析器实例
     * @return ITokenHandler 匹配的令牌处理器或非法令牌处理器
     */
    public function getHandler(Lexer $lexer): ITokenHandler
    {
        // 使用 map 提高单字符的 Handler 的查找效率
        if (isset(self::$charToHandlerMap[$lexer->getCurrentChar()])) {
            return self::$charToHandlerMap[$lexer->getCurrentChar()];
        }
        // 遍历所有处理器查找
        $handlers = $this->getHandlers();
        foreach ($handlers as $handler) {
            if ($handler->canHandle($lexer)) {
                return $handler;
            }
        }
        return new IllegalHandler();
    }

    /**
     * 获取所有注册的令牌处理器列表
     *
     * @return ITokenHandler[] 令牌处理器数组
     */
    private static function getHandlers(): array
    {
        if (!empty(self::$handlers)) {
            return self::$handlers;
        }
        self::$handlers = array(
            new AssignHandler(),
            new BandHandler(),
            new LessThanHandler(),
            new GreaterThanHandler(),
            new EqualHandler(),
            new NotEqualHandler(),
            new LessThanEqualHandler(),
            new GreaterThanEqualHandler(),
            new LogicalAndHandler(),
            new LogicalOrHandler(),
            new StringHandler(),
            new FunctionHandler(),
            new LetHandler(),
            new TrueHandler(),
            new FalseHandler(),
            new IfHandler(),
            new ElseHandler(),
            new ReturnHandler(),
            new IdentifierHandler(),
            new MinusHandler(),
            new NumberHandler(),
            new IllegalHandler(),
            new EofHandler(),
        );
        return self::$handlers;
    }
}